/**
 * 
 */
package org.dragonfire.editor;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

import org.dragonfire.ti.TIFile;
import org.dragonfire.ti.VarEntry;
import org.dragonfire.util.token.Token;
import org.dragonfire.util.token.TokenInputStream;
import org.dragonfire.util.token.TokenOutputStream;
import org.dragonfire.util.token.TokenTable;
import org.eclipse.core.filebuffers.manipulation.ContainerCreator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.editors.text.FileDocumentProvider;
import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;

/**
 * @author Darth Android
 * @date Oct 8, 2007
 */
public class TIFileDocumentProvider extends FileDocumentProvider {

	/**
	 * 
	 */
	public TIFileDocumentProvider() {
	}

	protected void setDocumentContent(IDocument document, InputStream contentStream, String encoding)
			throws CoreException {
		if (document instanceof TIDocument) {
			try {

				TIFile tif = new TIFile(contentStream); // read file
				TokenTable table = TIFile.getTokenTable(tif.getCalcType());
				VarEntry ve = tif.getVars().get(0);
				TIDocument doc = (TIDocument) document;
				doc.setCalcType(tif.getCalcType());
				doc.setVarType(ve.getType());
				String name = ve.getName();
				Byte[] nameBytes = new Byte[name.length()];
				for (int i = 0; i < name.length(); i++) {
					nameBytes[i] = (byte) name.charAt(i);
				}
				Token[] nameToks = table.readTokens(nameBytes);
				String nameText = "";
				for (Token t : nameToks) {
					nameText += t.getEditText();
				}
				doc.setVarName(nameText);
				switch (ve.getType()) {
					case TIFile.TYPE_PROGRAM:
					case TIFile.TYPE_PROTECTED_PROGRAM:
						InputStream is = ve.dataAsInputStream();
						is.read();
						is.read();
						TokenInputStream stream = new TokenInputStream(table, is, true, Charset.defaultCharset().name());
						super.setDocumentContent(document, stream, null);
						stream.close();
						break;

				}

			} catch (CoreException ce) {
				throw ce;
			} catch (Exception x) {
				String message = (x.getMessage() != null ? x.getMessage() : ""); //$NON-NLS-1$
				IStatus s = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.OK, message, x);
				throw new CoreException(s);
			}
		}
		else
			super.setDocumentContent(document, contentStream, encoding);
	}

	protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
			throws CoreException {
		if (element instanceof IFileEditorInput && document instanceof TIDocument) {
			TIDocument doc = (TIDocument) document;
			IFileEditorInput input = (IFileEditorInput) element;
			FileInfo info = (FileInfo) getElementInfo(element);
			IFile file = input.getFile();
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			TokenOutputStream tos = new TokenOutputStream(TIFile.getTokenTable(TIFile.CALC_8X), bos);
			try {
				tos.write(document.get().getBytes());
				tos.flush();
				TIFile tif = new TIFile(doc.getCalcType(), "Created by Eclipse");
				byte[] tokens = bos.toByteArray();
				Byte[] sizeNTokens = new Byte[tokens.length + 2];
				sizeNTokens[0] = (byte) (tokens.length & 0xFF);
				sizeNTokens[1] = (byte) ((tokens.length >> 8) & 0xFF);
				System.arraycopy(tokens, 0, sizeNTokens, 2, tokens.length);
				tif.addVarEntry(new VarEntry(doc.getCalcType(), doc.getVarType(), doc.getVarName(), sizeNTokens));
				ByteArrayInputStream stream = new ByteArrayInputStream(tif.buildFile());
				tos.close();
				bos.close();
				if (file.exists()) {

					if (info != null && !overwrite)
						checkSynchronizationState(info.fModificationStamp, file);

					// inform about the upcoming content change
					fireElementStateChanging(element);
					try {
						file.setContents(stream, overwrite, true, monitor);
					} catch (CoreException x) {
						// inform about failure
						fireElementStateChangeFailed(element);
						throw x;
					} catch (RuntimeException x) {
						// inform about failure
						fireElementStateChangeFailed(element);
						throw x;
					}

					// If here, the editor state will be flipped to "not dirty".
					// Thus, the state changing flag will be reset.

					if (info != null) {

						ResourceMarkerAnnotationModel model = (ResourceMarkerAnnotationModel) info.fModel;
						if (model != null)
							model.updateMarkers(info.fDocument);

						info.fModificationStamp = computeModificationStamp(file);
					}

				}
				else {
					try {
						monitor.beginTask("Saving...", 2000); // LAME ECLIPSE
						// WON'T SHARE
						// RESOURCES!
						ContainerCreator creator = new ContainerCreator(file.getWorkspace(), file.getParent()
								.getFullPath());
						creator.createContainer(new SubProgressMonitor(monitor, 1000));
						file.create(stream, false, new SubProgressMonitor(monitor, 1000));
					} finally {
						monitor.done();
					}
				}
			} catch (IOException e) {
				Status status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, "I/O Exception", e);
				throw new CoreException(status);
			}

		}
		else {
			super.doSaveDocument(monitor, element, document, overwrite);
		}
	}

	public IDocument createEmptyDocument() {
		return new TIDocument();
	}

}
